#第五章 一等函数

'''
人们经常将“把函数视作一等对象”简称为“一等函数”。这样说并不完美，
似乎表明这是函数中的特殊群体。在Python 中，所有函数都是一等对象。

'''

print(sum(range(101)))

s = "banana"
print(s[::-1])

class BingoCage():
    def __call__(self,v): #实现了 __call__ 方法 该类的实例可以被当作函数调用
        return v*2
bg = BingoCage()
print(bg(2),callable(bg))

#生成任意html标签的函数
def tag(name,*content,cls='df_cls',**attrs): #分别是必须参数,可变参数,命名关键字参数，关键字参数
    content_s = ""
    if content:       
        content_s = " ".join(content)
    attr_s = ""
    if  cls:
        attr_s += "class='"+cls+"' "
    if attrs:
        for k,v in attrs.items():
            attr_s+=k+"='"+v+"' "    
    return "<%s %s >%s</%s>" %(name,attr_s,content_s,name)

print('tag',tag('span'))
print('tag',tag('img',src='a.jpg',cls='imgCls')) #传入关键字参数

my_tag = {"name":"div",'cls':'mainView','color':'#cccc00'}

print(tag(**my_tag)) # 对dict拆包传参

my_cnt = ['wellcome','to','china']
print(tag('div',*my_cnt)) # 对 list 拆包传参

# 审查函数

def clip(text:str,max_len:int=80,**args)->str: #注意返回值的注解写法
    name = 'kfz'
    print(max_len,args)
    return name

clip('hello',50,age=18)
print('__annotations__=',clip.__annotations__) # 返回函数的注解 注意不是我们写的代码文档注释
print(clip.__defaults__) # 定位参数 和 关键字参数的默认值。
print(clip.__kwdefaults__) # 得到命名关键字参数的默认值
print(tag.__kwdefaults__) # 得到命名关键字参数的默认值
print(clip.__code__.co_varnames) #得到函数中所有的变量名称 包括参数名称 函数体内定义的变量名称 前N个表示函数参数的名称
print(clip.__code__.co_argcount) #得到函数参数的个数

# 通过inspect模块查找函数的参数名称和默认值 

from inspect import signature

sig = signature(tag)

print(sig)
paramItems = sig.parameters.items() # 函数的参数信息

for name,param in paramItems: #打印出函数参数相关的信息
    print('--------- inspect name=',name,'value=',param.default,'kind=',param.kind)

from functools import reduce,partial,partialmethod

print(reduce(lambda x,y:x*y,[1,2,3,4,5])) # reduce 函数先对列表的前两个元素传入参数函数中 然后把结果和下一个元素继续传入参数函数中进行操作

#通过reduce实现n的阶乘

def fact(n):
    ary = range(1,n+1)    
    return reduce(lambda x,y:x*y,ary)

print(fact(5))

from operator import itemgetter,attrgetter

ary = [('100','jz'),('120','gd'),('90','sh'),('80','qd')]
getName = itemgetter(1) # 定义获取列表的规则（返回第二个元素）
print('itemgetter',getName(ary[0]))

#利用itemgetter进行字段名排序
ary.sort(key=itemgetter(1))
print(ary)

# attrgetter 用法和itemgetter类似 不过是根据字段名获取而不是根据下标

# partial的使用 可以从一个已经存在的函数派生出一个设置固定参数值的函数

def fn(a,b,c):
    return a*b*c

fn2 = partial(fn,2,3) #固定 a、b参数的值
print(fn2(4))